package org.springframework.aop.org.springframework.aop.framework.aotoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.org.springframework.aop.AdvisedSupport;
import org.springframework.aop.org.springframework.aop.ClassFilter;
import org.springframework.aop.org.springframework.aop.TargetSource;
import org.springframework.aop.org.springframework.aop.framework.DefaultAopProxyFactory;
import org.springframework.aop.org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor;
import org.springframework.aop.org.springframework.aop.framework.aspectj.AspectExpressionPointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.test.domain.User;

import java.util.List;

/**
 * aop
 *
 * @author admin
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private ConfigurableListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        List<AspectExpressionPointcutAdvisor> list = beanFactory.getBeanOfType(AspectExpressionPointcutAdvisor.class);
        // 添加aop事件
        String expression = "execution(* org.springframework.test.domain.*.*(..))";
        AspectExpressionPointcutAdvisor aspectAdvisor = new AspectExpressionPointcutAdvisor(expression);
        aspectAdvisor.setAdvice(new MethodBeforeAdviceInterceptor((method, args, target) -> {
            System.out.println("你被前置代理了");
        }));
        list.add(aspectAdvisor);
        for (AspectExpressionPointcutAdvisor advisor : list) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            if (!classFilter.matches(beanClass)) {
                continue;
            }

            AdvisedSupport advised = new AdvisedSupport();
            TargetSource targetSource = null;
            try {
                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
            }catch (Exception e) {
                e.printStackTrace();
            }
            advised.setTargetSource(targetSource);
            advised.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advised.setInterceptor((MethodInterceptor) advisor.getAdvice());
            advised.setProxyTargetClass(true);
            return new DefaultAopProxyFactory(advised).createAopProxy().getProxy();
        }
        return null;
    }
}
